package cn.kust.gateway.filter;

import cn.hutool.core.util.ReUtil;
import cn.kust.microtourismcommon.constant.CommonStatusEnum;
import cn.kust.microtourismcommon.constant.TokenConstants;
import cn.kust.microtourismcommon.pojo.dto.ResponseResult;
import cn.kust.microtourismcommon.pojo.dto.TokenResult;
import cn.kust.microtourismcommon.util.JwtUtils;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author WY
 * @data 2022/8/15 9:55
 **/
@Component
@Slf4j
public class TokenFilter implements Ordered, GlobalFilter {


    @Data
    @Component

    @ConfigurationProperties(prefix = "interceptions.path") // 配置文件的前缀
     class InterceptorPathBean {
        /*
         * 需要拦截的路径
         */
        // 白名单，无需验证token
        // list集合数据不能使用value来获取，需要定义对象获取
        private List<String> whitelist;
        // 验证名单，需要验证token才能访问
        private List<String> verifies;
    }

    @Autowired
    private InterceptorPathBean interceptorPathBean;
    /**
     *
     * @param exchange 拿request 和response
     * @param chain  过滤链
     * @return  是否放行
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestPath = request.getURI().getPath();
        //如果是白名单就不进行拦截

        log.debug("载入验证名单。。。。。。");
        log.debug("白名单： " + interceptorPathBean.whitelist.toString());
        log.debug("验证名单： " + interceptorPathBean.verifies.toString());

        //优化索引速度
        HashSet<String> whitelistHashSet = new HashSet<>(interceptorPathBean.whitelist);
        HashSet<String> verifiesHashSet = new HashSet<>(interceptorPathBean.verifies);
        AtomicBoolean whiteListFlag = new AtomicBoolean(false);
        AtomicBoolean verifiesFlag = new AtomicBoolean(false);

        whitelistHashSet.stream().forEach(whitelist -> {
            if (ReUtil.isMatch(whitelist,requestPath)){
                whiteListFlag.set(true);
            }

        });

        verifiesHashSet.stream().forEach(verfies -> {
            if (ReUtil.isMatch(verfies,requestPath)){
                verifiesFlag.set(true);
            }
        });
//        System.out.println(ReUtil.isMatch("/userCenter/users/.*","/userCenter/users/1/5"));


        log.debug("当前目标请求路径：" + requestPath );

        //目标请求路径在白名单上不进行拦截
        if (whiteListFlag.get()){
            log.debug("当前请求无需解析token！ 正在转发。。。。");
            return chain.filter(exchange);
        }
        // 目标路径在验证名单上进行token的验证
        if(verifiesFlag.get()){
            String token = request.getHeaders().getFirst(TokenConstants.TOKEN_REQUEST_KEY);
            log.debug("token为：" + token);

            //判断token是否合法（非空判断 合法判断 过期判断）
            //非空

            if (StringUtils.isEmpty(token)){

                return denyAccess(exchange,CommonStatusEnum.TOKEN_IS_EMPTY);
            }

            //如果token非法，返回token非法
            try {
                TokenResult tokenResult = JwtUtils.parseToken(token);
            } catch (Exception e) {
                log.debug("token 非法！");
                log.debug(e.toString());
                return denyAccess(exchange,CommonStatusEnum.TOKEN_ERROR);
            }

            log.debug("token解析成功！");
            TokenResult tokenResult = JwtUtils.checkToken(token);
            log.debug("用户id为：" + tokenResult.getUserId());
            log.debug("用户id为：" + tokenResult.getPhone());
            log.debug("用户id为：" + tokenResult.getIdentity());

            //通过判断，将用户信息设置到header中，传递到下游服务
            ServerHttpRequest mutableReq = request.mutate()
                    .header("phone", tokenResult.getPhone())
                    .header("userId",tokenResult.getUserId())
                    .header("identity",tokenResult.getIdentity())
                    .build();
            ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();

            return chain.filter(mutableExchange);
        }


        // 请求非法，
        log.debug("请求未通过验证，检查是否为白名单对象或者检查token情况");
        return denyAccess(exchange, CommonStatusEnum.ILLEGAL_URL_ERROR);


    }


    //如果不符合条件不给放行并且返回拦截信息
    private Mono<Void> denyAccess(ServerWebExchange exchange, CommonStatusEnum commonStatus){
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        byte[] bytes = JSON.toJSONBytes(ResponseResult.fail(commonStatus.getCode(), commonStatus.getValue()));
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return 0;
    }





}
